package strategy

import (
	"fmt"
)

type CompositeStrategy struct {
	strategies []Strategy
}

// Evaluate implements Strategy.
func (s *CompositeStrategy) Evaluate(current MultiObjectiveScore, link *LinkWithAttrs) MultiObjectiveScore {
	panic("unimplemented")
}

// GetType implements Strategy.
func (s *CompositeStrategy) GetType() ConstraintType {
	panic("unimplemented")
}

func NewCompositeStrategy(strategies []Strategy) *CompositeStrategy {
	return &CompositeStrategy{
		strategies: strategies,
	}
}

func (s *CompositeStrategy) GetConstraint() []ConstraintType {
	types := make([]ConstraintType, len(s.strategies))
	for i, st := range s.strategies {
		types[i] = st.GetType()
	}
	return types
}

func (s *CompositeStrategy) CalculatePath(graph *Graph, source, destination string) (*Path, error) {
	scoreFunc := func(link *LinkWithAttrs, current MultiObjectiveScore) MultiObjectiveScore {
		score := current
		for _, strategy := range s.strategies {
			score = strategy.Evaluate(score, link)
		}
		return score
	}

	initialScore := make(MultiObjectiveScore, len(s.strategies))
	for i := range initialScore {
		initialScore[i] = 0.0
	}

	path, visitedMap, err := multiObjectiveDijkstraWithVisitLog(graph, source, destination, scoreFunc, initialScore)
	if err != nil {
		return nil, err
	}

	// 验证每个策略是否满足
	for _, strategy := range s.strategies {
		if !strategy.Apply(path, visitedMap) {
			return nil, fmt.Errorf("策略校验失败: %T", strategy)
		}
	}

	return path, nil
}
